import { DRACOLoader, GLTFLoader, KTX2Loader } from 'three/addons';
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module.js';
import type { LoadingManager } from 'three/webgpu';

type TypeFileFlatMap = Map<string, File>;

type TypeGetFilesFromItemListOnDone = (files: File[], flatMap: TypeFileFlatMap) => void;

const createFilesMap = (files: File[]) => {
  const map: TypeFileFlatMap = new Map();
  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    map.set(file.name, file);
  }
  return map;
};

const getFilesFromItemList = (items: DataTransferItemList, onDone: TypeGetFilesFromItemListOnDone) => {
  let itemsCount = 0;
  let itemsTotal = 0;

  const files: File[] = [];
  const filesMap: TypeFileFlatMap = new Map();

  function onEntryHandled() {
    itemsCount++;
    if (itemsCount === itemsTotal) {
      onDone(files, filesMap);
    }
  }

  function handleEntry(entry: FileSystemEntry) {
    if (entry.isDirectory) {
      const reader = (entry as FileSystemDirectoryEntry).createReader();
      reader.readEntries((entries) => {
        for (let i = 0; i < entries.length; i++) {
          handleEntry(entries[i]);
        }
        onEntryHandled();
      });
    } else if (entry.isFile) {
      (entry as FileSystemFileEntry).file((file) => {
        files.push(file);
        filesMap.set(entry.fullPath.slice(1), file);
        onEntryHandled();
      });
    }
    itemsTotal++;
  }

  for (let i = 0; i < items.length; i++) {
    const item = items[i];
    if (item.kind === 'file') {
      const entry = item.webkitGetAsEntry();
      if (!entry) continue;
      handleEntry(entry);
    }
  }
};

let gltfLoader: GLTFLoader | null = null;
const createGLTFLoader = (manager?: LoadingManager) => {
  if (gltfLoader) return gltfLoader;
  const dracoLoader = new DRACOLoader();
  dracoLoader.setDecoderPath('three/examples/jsm/libs/draco/gltf/');

  const ktx2Loader = new KTX2Loader(manager);
  ktx2Loader.setTranscoderPath('three/examples/jsm/libs/basis/');

  gltfLoader = new GLTFLoader(manager);
  gltfLoader.setDRACOLoader(dracoLoader);
  gltfLoader.setKTX2Loader(ktx2Loader);
  gltfLoader.setMeshoptDecoder(MeshoptDecoder);

  return gltfLoader;
};

export default { createFilesMap, getFilesFromItemList, createGLTFLoader };

export type { TypeFileFlatMap, TypeGetFilesFromItemListOnDone };
